package com.muyu.service.impl;

import com.muyu.api.exception.BusinessException;
import com.muyu.api.model.enums.ApiStatusEnum;
import com.muyu.model.dto.GetDBInfoByPageDTO;
import com.muyu.service.DBService;
import com.muyu.model.dto.GetDBInfoDTO;
import com.muyu.util.BaseDao;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.sql.*;
import java.util.*;

/**
 * @ClassName: DBServiceImpl
 * @Author: Zirun.Xin
 * @Date: 2025/4/16 上午9:19
 * @Description: 数据库业务实现层
 */
@Service
@RequiredArgsConstructor
public class DBServiceImpl implements DBService {

    /**
     * 持久层基类
     */
    private final BaseDao baseDao;

    /**
     * 获取数据库表数据
     * @param getDBInfoDTO 包含数据库连接信息和表名的数据传输对象
     * @return 返回包含表数据的List，每个Map表示一行数据，key为列名，value为对应的值
     * @throws BusinessException 当数据库操作失败时抛出
     */
    @Override
    public List<Map<String, String>> getDBInfo(GetDBInfoDTO getDBInfoDTO) {
        String sql = String.format("SELECT * FROM %s", getDBInfoDTO.getTableName());

        try (Connection conn = baseDao.getConn(getDBInfoDTO.getDbUrl(),
                getDBInfoDTO.getUserName(),
                getDBInfoDTO.getPassWord(),
                getDBInfoDTO.getDriverClass());
             PreparedStatement ps = conn.prepareStatement(sql);
             ResultSet rs = ps.executeQuery()) {

            return collectResultData(rs, getColumnNames(rs.getMetaData()));
        } catch (SQLException e) {
            throw BusinessException.of(ApiStatusEnum.INTERNAL_ERROR);
        }
    }

    /**
     * 获取数据库表分页数据
     * @param getDBInfoByPageDTO 包含数据库连接分页信息和表名的数据传输对象
     * @return 页码信息包含当前页面数据
     */
    @Override
    public Map<String, Object> getDBInfoByPage(GetDBInfoByPageDTO getDBInfoByPageDTO) {
        // 获取参数信息
        String dbUrl = getDBInfoByPageDTO.getDbUrl();
        String userName = getDBInfoByPageDTO.getUserName();
        String passWord = getDBInfoByPageDTO.getPassWord();
        String driverClass = getDBInfoByPageDTO.getDriverClass();
        String tableName = getDBInfoByPageDTO.getTableName();
        int limit = getDBInfoByPageDTO.getLimit();
        int page = getDBInfoByPageDTO.getPage();

        // 计算sql分页起始下标
        int pageStartIndex = (getDBInfoByPageDTO.getPage() - 1) * limit;

        // 定义sql语句
        String sql = String.format("SELECT * FROM %s LIMIT %d,%d", tableName, pageStartIndex, limit);

        try(Connection conn = baseDao.getConn(dbUrl, userName, passWord, driverClass);
            PreparedStatement ps = conn.prepareStatement(sql);
            ResultSet rs = ps.executeQuery()) {
            ResultSetMetaData metaData = rs.getMetaData();

            return this.getPageInfo(
                    page,
                    limit,
                    this.getDBInfo(GetDBInfoDTO.builder().dbUrl(dbUrl).userName(userName)
                            .passWord(passWord).driverClass(driverClass).tableName(tableName)
                            .build()).size(),
                    this.collectResultData(rs, this.getColumnNames(metaData))
            );
        } catch (SQLException e) {
            throw BusinessException.of(ApiStatusEnum.INTERNAL_ERROR);
        }
    }

    /**
     * 从ResultSet元数据中获取列名列表
     * @param metaData 结果集的元数据对象
     * @return 包含所有列名的列表
     * @throws SQLException 当获取列名失败时抛出
     */
    private List<String> getColumnNames(ResultSetMetaData metaData) throws SQLException {
        List<String> columns = new ArrayList<>();
        for (int i = 1; i <= metaData.getColumnCount(); i++) {
            columns.add(metaData.getColumnName(i));
        }
        return columns;
    }

    /**
     * 从ResultSet中收集数据并转换为List<Map>格式
     * @param rs 数据库查询结果集
     * @param columns 列名列表
     * @return 包含所有行数据的List，每行数据以Map形式存储
     * @throws SQLException 当读取结果集数据失败时抛出
     */
    private List<Map<String, String>> collectResultData(ResultSet rs, List<String> columns) throws SQLException {
        List<Map<String, String>> result = new ArrayList<>();
        while (rs.next()) {
            Map<String, String> row = new LinkedHashMap<>();
            for (String column : columns) {
                row.put(column, rs.getString(column));
            }
            result.add(row);
        }
        return result;
    }

    /**
     * 获取分页信息
     * @param current 当前页数
     * @param size 分页条数
     * @param total 总条数
     * @param records 数据
     * @return 分页信息
     */
    private Map<String, Object> getPageInfo(int current, int size, int total, Object records) {
        // 计算总页数
        int pages = total % size == 0 ? total / size : total / size + 1;
        // 计算是否有下一页
        boolean hasNext = current < pages;

        // 定义分页信息
        LinkedHashMap<String, Object> resultMap = new LinkedHashMap<>();
        resultMap.put("current", current);
        resultMap.put("size", size);
        resultMap.put("total", total);
        resultMap.put("pages", pages);
        resultMap.put("hasNext", hasNext);
        resultMap.put("records", records);

        return resultMap;
    }
}
